﻿using Core;
using Core.Domain.Entities;
using Core.Domain.Events;
using Core.Domain.ValueObjects;
using Core.Identity.Common.Interfaces.Common.Interfaces;
using Finbuckle.MultiTenant;
using Finbuckle.MultiTenant.Abstractions;
using Infrastructure.Tenant;
using Mapster;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Infrastructure.Persistence.EventHandler;

public class AssignPermissionToTenantEventHandler(
    ILogger<AssignPermissionToTenantEventHandler> logger,
            IServiceProvider serviceProvider,
            IMultiTenantStore<BoilerplateTenantInfo> tenantStore,
            IIdentityDbContext dbContext)
    : INotificationHandler<AssignPermissionToTenantEvent>
{
    public async Task Handle(AssignPermissionToTenantEvent notification,
        CancellationToken cancellationToken)
    {
        logger.LogInformation("正在处理租户权限创建的域事件...");

        var permissions = new List<Permission>();
        if (notification.TenantPermissions != null && notification.TenantPermissions.Any())
        {
            permissions = await dbContext.Permissions
                .AsNoTracking()
                .Where(x => notification.TenantPermissions.Contains(x.Id))
                .ToListAsync(cancellationToken);
        }

        var tenant = await tenantStore.TryGetAsync(notification.TenantId);

        using var scope = serviceProvider.CreateScope();
        scope.ServiceProvider.GetRequiredService<IMultiTenantContextSetter>()
            .MultiTenantContext = new MultiTenantContext<BoilerplateTenantInfo>()
            {
                TenantInfo = tenant
            };

        var context = scope.ServiceProvider.GetService<IIdentityDbContext>();
        if (context == null)
        {
            logger.LogError("处理租户权限创建的域事件失败...");
            throw new BoilerplateException();
        }

        //把数据同步到租户数据库做记录
        var tenantPermissionsToArchive = await context.TenantPermissions
           .Where(x => x.BoilerplateTenantInfoId == notification.TenantId)
           .ToListAsync();
        if (tenantPermissionsToArchive.Count != 0)
        {
            var historyRecords = tenantPermissionsToArchive.Adapt<List<TenantPermissionHistory>>();
            await context.TenantPermissionHistories.AddRangeAsync(historyRecords);
            context.TenantPermissions.RemoveRange(tenantPermissionsToArchive);
        }
        if (notification.TenantPermissions != null && notification.TenantPermissions.Any())
        {
            var newTenantPermissionsToCreate = new List<TenantPermission>();
            foreach (var permissionId in notification.TenantPermissions)
            {
                var tenantPermission = new TenantPermission()
                {
                    BoilerplateTenantInfoId = notification.TenantId,
                    PermissionId = permissionId,
                    AssignmentBatchId = notification.BatchId,
                };
                newTenantPermissionsToCreate.Add(tenantPermission);
            }
            await context.TenantPermissions.AddRangeAsync(newTenantPermissionsToCreate);
        }


        //根据权限判断是否需要新增
        if (permissions != null && permissions.Count != 0)
        {
            var tenantPermissions = await context.Permissions.ToListAsync();
            if (tenantPermissions != null && tenantPermissions.Count > 0)
            {
                permissions = permissions
                    .Where(x => !tenantPermissions
                    .Select(s => s.SourcePermissionId)
                    .Contains(x.Id))
                    .ToList();

            }
            if (!permissions.Any()) { return; }
            var time = DateTimeOffset.UtcNow;
            var menus = new List<Permission>();

            foreach (var item in permissions!)
            {
                var meta = new MenuMeta(
                    menuType: item.MenuType!.Value,
                    title: item.Title,
                    name: item.RouteName,
                    path: item.Path,
                    component: item.Component,
                    rank: item.Rank!.Value,
                    redirect: item.Redirect,
                    icon: item.Icon,
                    extraIcon: item.ExtraIcon,
                    enterTransition: item.EnterTransition,
                    leaveTransition: item.LeaveTransition,
                    activePath: item.ActivePath,
                    frameSrc: item.FrameSrc,
                    frameLoading: item.FrameLoading!.Value,
                    keepAlive: item.KeepAlive!.Value,
                    hiddenTag: item.HiddenTag!.Value,
                    fixedTag: item.FixedTag!.Value,
                    showLink: item.ShowLink!.Value,
                    showParent: item.ShowParent!.Value);

                var menu = Permission.Create(
                    code: item.Code,
                    name: item.Name,
                    meta: meta,
                    parentId: item.ParentId,
                    group: item.Group);
                menu.Id = item.Id;
                menu.Description = item.Description;
                menu.Sort = item.Sort;
                menu.Created = time;
                menu.CreatedBy = null;
                menu.CreatedByName = null;
                menu.ChangeScope(item.Scope);
                menu.ChangeSourcePermission(item.Id);
                menus.Add(menu);
            }

            if (menus.Any())
            {
                // 1 创建字典：记录旧 Id 到新 Id 的映射
                var idMap = new Dictionary<Guid, Guid>();

                // 2 第一次遍历：为每条记录生成新 Id，并建立映射
                foreach (var item in menus)
                {
                    var oldId = item.Id;
                    var newId = Guid.CreateVersion7(DateTimeOffset.UtcNow); // 或使用雪花算法等分布式 ID
                    idMap[oldId] = newId;
                    item.Id = newId; // 更新自身 Id
                }

                // 3 第二次遍历：更新 ParentId，根据映射关系找到新的父级 Id
                foreach (var item in menus)
                {
                    if (item.ParentId.HasValue && idMap.TryGetValue(item.ParentId.Value, out var newParentId))
                    {
                        item.ChangeParent(newParentId);
                    }
                }
                await context.Permissions.AddRangeAsync(menus, cancellationToken);
            }
        }

        await context.SaveChangesAsync();
        await Task.FromResult(notification);
        logger.LogInformation("已完成处理租户权限创建的域事件...");
    }
}
